#include <stdio.h>
#include <strings.h>
#include <string.h>
#include <stddef.h>
#include <stdlib.h>
#include <unistd.h>
#include <assert.h>
#include <sys/mman.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <ctype.h>
#include <inttypes.h>

#include "map_reduce.h"
#include "stddefines.h"
#include "histogram.h"


bool load_bitmap_header(char *pFileName, BITMAPFILEHEADER* pBmpFileHdr , BITMAPINFOHEADER* pBmpInfoHdr)
{
	int i;
	LONG nBitsSize, nBISize;
	//BITMAPFILEHEADER* pBmpFileHdr = new BITMAPFILEHEADER;
	LONG nBytes;
	FILE *fp=fopen(pFileName,"rb");

	if(fp==NULL)return false;

	// Read the file header.  This will tell us the file size and
	// where the data bits start in the file.
	//printf("size of BITMAPFILEHEADER is %d\n", sizeof(BITMAPFILEHEADER));

	//nBytes = fread(&BmpFileHdr, 1, sizeof(BITMAPFILEHEADER), fp);
	//if ( nBytes != sizeof(BITMAPFILEHEADER) )
	fread(&pBmpFileHdr->bfType, 1, 2, fp);
	fread(&pBmpFileHdr->bfSize, 1, 4, fp);
	fread(&pBmpFileHdr->bfReserved1, 1, 2, fp);
	fread(&pBmpFileHdr->bfReserved2, 1, 2, fp);
	fread(&pBmpFileHdr->bfOffBits, 1, 4, fp);

	//printf("FileSize = %x\n", pBmpFileHdr->bfSize);

	// Do we have "BM" at the start indicating a bitmap file?
	if ( pBmpFileHdr->bfType != 0x4D42 )
	{
		fclose(fp);
		return false;
	}

	// Assume for now that the file is a Wondows DIB.
	// Read the BITMAPINFOHEADER.
	//BITMAPINFOHEADER * pBmpInfoHdr = new BITMAPINFOHEADER;
	nBytes = fread(pBmpInfoHdr, 1, sizeof(BITMAPINFOHEADER), fp);
	//printf("size of BITMAPINFOHEADER is %d\n", sizeof(BITMAPINFOHEADER));
	if ( nBytes != 40 )
	{
		fclose(fp);
		return false;
	}

	//only support BGR24 Windows DIB file
	if((pBmpInfoHdr->biBitCount!=24)||(pBmpInfoHdr->biSize != sizeof(BITMAPINFOHEADER)))
	{
		fclose(fp);
		return false;
	}

	fclose(fp);
	return true;
}

/* valcmp
 * Comparison function
 */
int valcmp(const void *v1, const void *v2)
{    
    short value1 = *((short *)v1);
    short value2 = *((short *)v2);
    
    if (value1 < value2) {
        return -1;
    }
    else if (value1 > value2) {
        return 1;
    }
    else {
        return 0;
    }
}


//hist_merger
void *hist_merger (iterator_t *iter)
{
  intptr_t sum = 0;
  void *value;

  while (iter_next (iter, &value)) {
    sum = sum + (intptr_t)value;
  }

  return (void *)sum;
}

// hist_mapper()
void hist_mapper(map_args_t *args) 
{
    int i;
    WORD *key;
    intptr_t red[256];
    intptr_t green[256];
    intptr_t blue[256];

    BYTE *data = (BYTE *)args->data;

    for(i=0; i< 256; i++) {
      blue[i] = 0;
      green[i] = 0;
      red[i] = 0;
    }

   
    for (i = 0; i < (args->length) * 3; i+=3) 
    {
      blue[data[i]] +=1;;
      green[data[i+1]] +=1;
      red[data[i+2]]+=1;    
    }
    
    for (i = 0; i < 256; i++) 
    {

        if (red[i] > 0) {
            key = (WORD *) &(red_keys[i]);
            emit_intermediate((void *)key, (void *)red[i], (int)sizeof(WORD));
        }
       
        if (green[i] > 0) {
            key = (WORD *) &(green_keys[i]);
            emit_intermediate((void *)key, (void *)green[i], (int)sizeof(WORD));
        }
        
        if (blue[i] > 0) {
	  key = (WORD *) &(blue_keys[i]);
            emit_intermediate((void *)key, (void *)blue[i], (int)sizeof(WORD));
        }
    }
}

//hist_reducer()
void hist_reducer(void *key_in, iterator_t *iter)
{
  void *value;
  intptr_t sum = 0;
  WORD *key = (WORD *)key_in;
  
  
  while (iter_next (iter, &value)) {
    sum = sum + (intptr_t)value;
  }
  
  emit(key, (void *)sum);
}

